package com.jhf.youke.stock.domain.service;

import com.jhf.youke.core.ddd.AbstractDomainService;
import com.jhf.youke.core.entity.PageQuery;
import com.jhf.youke.core.entity.Pagination;
import com.jhf.youke.core.utils.CacheUtils;
import com.jhf.youke.stock.domain.converter.StockConverter;
import com.jhf.youke.stock.domain.exception.StockException;
import com.jhf.youke.stock.domain.gateway.StockRepository;
import com.jhf.youke.stock.domain.model.Do.StockDo;
import com.jhf.youke.stock.domain.model.dto.StockDto;
import com.jhf.youke.stock.domain.model.po.StockPo;
import com.jhf.youke.stock.domain.model.vo.StockVo;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author  RHJ
 **/

@Service
public class StockService extends AbstractDomainService<StockRepository, StockDo, StockVo> {


    @Resource
    StockConverter stockConverter;

    @Override
    public boolean update(StockDo entity) {
        StockPo stockPo = stockConverter.do2Po(entity);
        stockPo.preUpdate();
        return repository.update(stockPo);
    }

    @Override
    public boolean updateBatch(List<StockDo> doList) {
        List<StockPo> poList = stockConverter.do2PoList(doList);
        return repository.updateBatch(poList);
    }

    @Override
    public boolean delete(StockDo entity) {
        StockPo stockPo = stockConverter.do2Po(entity);
        return repository.delete(stockPo);
    }

    @Override
    public boolean deleteBatch(List<Long> idList) {
        return repository.deleteBatch(idList);
    }

    @Override
    public boolean insert(StockDo entity) {
        StockPo stockPo = stockConverter.do2Po(entity);
        stockPo.preInsert();
        return repository.insert(stockPo);
    }

    @Override
    public boolean insertBatch(List<StockDo> doList) {
        List<StockPo> poList = stockConverter.do2PoList(doList);
        StockPo.getInsertListId(poList);
        return repository.insertBatch(poList);
    }

    @Override
    public Optional<StockVo> findById(Long id) {
        Optional<StockPo> stockPo =  repository.findById(id);
        StockVo stockVo = stockConverter.po2Vo(stockPo.orElse(new StockPo()));
        return Optional.ofNullable(stockVo);
        
    }

    @Override
    public boolean remove(Long id) {
        return repository.remove(id);
    }

    @Override
    public boolean removeBatch(List<Long> idList) {
        return repository.removeBatch(idList);
    }

    @Override
    public List<StockVo> findAllMatching(StockDo entity) {
        StockPo stockPo = stockConverter.do2Po(entity);
        List<StockPo>stockPoList =  repository.findAllMatching(stockPo);
        return stockConverter.po2VoList(stockPoList);
    }


    @Override
    public Pagination<StockVo> selectPage(StockDo entity){
        StockPo stockPo = stockConverter.do2Po(entity);
        PageQuery<StockPo> pageQuery = new PageQuery<>(stockPo,entity.getCurrentPage(), entity.getPageSize(), entity.getQuerySort());
        Pagination<StockPo> pagination = repository.selectPage(pageQuery);
        return new Pagination<>(pagination.getPageNum(),pagination.getPageSize(),pagination.getTotalSize(),
                stockConverter.po2VoList(pagination.getList()));
    }

    public List<StockPo> getListByProductId(StockDto stockDto){
        return repository.getListByProductId(stockDto.getWarehouseId(),stockDto.getProductIds(),stockDto.getSpecs());
    }

    /**
    * @Description: 先进先出处理
     *  1. 先将申请需求进行汇总，分类两类, 一类带规格， 一类不带规格
     *  2。 处理之前使用warehouseId进行redis分布式锁
     *  3. 根据warehouseId, ProductIds查询库存
     *  4. 先处理带规格的需求，进行库存检查，库存如果不足，业务异常，库存如果足够则进行预冻结
     *  5。 再处理不带规格的需求，同上
     *  6。 处理完成后将两类需求合并，传给库存冻结
     *  7。 所有事务在APP层进行控制
    * @Param: []
    * @return: void
    * @Author: RHJ
    * @Date: 2023/6/24
    */
    public List<StockDo> freezeStock(StockDo stockDo){
        List<StockDo> result = new ArrayList<>();
        if(stockDo.getOutType() == 1){
            result = stockFrostByFIFO(stockDo);
        }else{
            result = stockFrostById(stockDo);
        }
        return result;
    }

    /**
    * @Description:  库存冻结先进先出
    * @Param: [stockDo]
    * @return: boolean
    * @Author: RHJ
    * @Date: 2023/6/26
    */
    public List<StockDo> stockFrostByFIFO(StockDo stockDo) throws StockException {

        String key = "warehouse_lock_" + stockDo.getWarehouseId();
        String requestId = stockDo.getWarehouseId().toString();
        Boolean lock = CacheUtils.lock(key, requestId, 5000);
        List<StockDo> stockDos ;
        try {
            Map<String, Map<String, BigDecimal>> stock = stockDo.sumStock();
            // 带规格的需求
            Map<String, BigDecimal> specsMap = stock.get("A");
            // 不带规格的需求
            Map<String, BigDecimal> resultMap = stock.get("B");
            // 需求产品ID
            Map<String, BigDecimal> productMap = stock.get("C");

            List<Long> ids = productMap.keySet()
                    .stream()
                    .map(Long::parseLong)
                    .collect(Collectors.toList());

            List<StockPo> stockPoList = repository.getListByProductId(stockDo.getWarehouseId(), ids, "");
            List<StockDo> stockDoList = stockConverter.po2DoList(stockPoList);

            stockDos = stockDo.specsCheckNum(specsMap, stockDoList);
            List<StockDo> comm_list = stockDo.commCheckNum(resultMap, stockDoList);
            stockDos.addAll(comm_list);
            updateBatch(stockDos);

        }finally {
            if(lock) {CacheUtils.release(key, requestId);}
        }

        return stockDos;
    }

    /**
    * @Description:  库存冻结根据库存ID
    * @Param: [stockDo]
    * @return: boolean
    * @Author: RHJ
    * @Date: 2023/6/26
    */
    public List<StockDo> stockFrostById(StockDo stockDo){
        return null;
    }

    public Map<String, Map<String, BigDecimal>> sumStock(StockDo stockDo){

        return stockDo.sumStock();
    }


}

